<?php
declare (strict_types = 1);

namespace app\home\controller;

use app\BaseController;
use app\common\model\Config as ConfigModel;
use app\common\model\Post\Cate as CateModel;
use app\common\model\Post\Comment as CommentModel;
use app\common\model\Post\Post as PostModel;
use app\common\model\User\Record as RecordModel;
use app\common\model\User\User as UserModel;
use think\captcha\facade\Captcha;
use app\common\validate\User\User as UserValidate;
use app\common\validate\User\Record as ReacrdValidate;
use think\exception\ValidateException;
use think\facade\View;
use think\facade\Db;
use app\common\model\User\Collection as CollectionModel;

class Index extends BaseController
{
    // 初始化
    protected function initialize()
    {
        parent::initialize();

        // 实例化用户模型
        $this->UserModel = new UserModel();
        // 实例化配置模型
        $this->ConfigModel = new ConfigModel();

        $this->CateModel = new CateModel();

        $this->RecordModel = new RecordModel();

        // 由于cookie只是存了一个userid，要通过userid去查询登录的数据
        $id = !empty(cookie('LoginUser')) ? cookie('LoginUser') : '';

        // 查询所有的用户id以及密码盐
        $userList = $this->UserModel->column('id,salt');

        // 存放用户id的变量
        $userid = 0;

        // 循环
        foreach ($userList as $item) {
            // 获取到id以及密码盐加密进行比对
            $ItemId = md5($item['id'] . $item['salt']);

            if($id == $ItemId)
            {
                $userid = $item['id'];
                break;
            }
        }

        // 查询登录用户的数据
        $user = $this->UserModel->find($userid);

        // 条件数组
        $where = [];

        // 查询当天内用户是否有签到记录
        if($user)
        {
            $where = [
                'userid' => $user['id'],
                'state' => 4
            ];

            $record = $this->RecordModel->whereDay('createtime')->where($where)->find();

            if($record == true)
            {
                $user['sign'] = true;
            }
        }

        $SystemList = ConfigModel::select();
        // halt($SystemList);

        // 定义一个空数组
        $System = [];

        foreach ($SystemList as $key => $item) {
            $System[$item['key']] = $item['value'];
        }

        // 赋值给所有的视图
        View::assign([
            'LoginUser' => $user,
            'System' => $System
        ]);

        // 赋值给所有的方法
        $this->LoginUser = $user;
    }

    // 首页
    public function index()
    {
        // 接收分类id
        $cateid = $this->request->param('cateid','all','trim');

        // 接收帖子状态
        $state = $this->request->param('state','all','trim');

        // 接收采纳
        $accept = $this->request->param('accept','');

        // 接收搜索关键字
        $keywords = $this->request->param('keywords','','trim');

        // 条件数组
        $where = [];

        // 分类
        if($cateid !== 'all')
        {
            $where[] = ['cateid','=',$cateid];
        }

        // 帖子状态
        if($state !== 'all')
        {
            $where[] = ['state','=',$state];
        }

        // 搜索
        if(!empty($keywords))
        {
            $where[] = ['title','like',$keywords];
        }

        // 采纳
        if(!empty($accept))
        {
            $where[] = ['accept','EXP',Db::raw('IS NOT NULL')];
        }else{
            $where[] = ['accept','EXP',Db::raw('IS NULL')];
        }
        
        // 查询帖子分类
        $CateList = $this->CateModel->order('weigh','desc')->limit(7)->select();

        // 查询帖子数据 paginate => 分页 
        $PostList = PostModel::withJoin(['user','cate'],'LEFT')->where($where)->order('createtime','desc')->paginate(['list_rows' => 6,'query' => request()->param()]);

        // 查询用户签到的获取积分
        $SignPoint = ConfigModel::where(['key' => 'SignPoint'])->value('value');
        $SignPoint = abs(intval($SignPoint)) ? abs(intval($SignPoint)) : 5;

        // 查询本周的热议帖子
        $PostWeek = CommentModel::withJoin(['post'],'LEFT')->field('count(*) as num,post.title,post.id,comment.id')->whereWeek('comment.createtime')->group('comment.postid')->order(['num'=>'desc'])->limit(10)->select();

        // 查询本周的回帖周榜
        $CommentWeek = CommentModel::withJoin(['user'],'LEFT')->field('count(*) as num,user.nickname,user.id,user.avatar')->whereWeek('comment.createtime')->group('comment.userid')->order(['num'=>'desc'])->limit(10)->select();

        return View::fetch('',[
            'CateList' => $CateList,
            'PostList' => $PostList,
            'PostWeek' => $PostWeek,
            'CommentWeek' => $CommentWeek,

            // 参数
            'cateid' => $cateid,
            'state' => $state,
            'accept' => $accept,
            'SignPoint' => $SignPoint
        ]);
    }

    // 帖子详情
    public function info()
    {
        // 接收帖子id
        $postid = $this->request->param('postid',0,'trim');

        // 查询帖子
        $post = PostModel::withJoin(['user','cate'],'LEFT')->find($postid);

        if(!$post)
        {
            $this->error('帖子不存在',(String)url('home/index/index'));
            
        }

        // 判断用户是否登录
        $LoginUser = !empty($this->LoginUser) ? $this->LoginUser : [];

        // 收藏的状态
        $CollectStatus = false;

        if(!empty($LoginUser))
        {
            // 用户Id
            $userid = !empty($LoginUser['id']) ? $LoginUser['id'] : 0;

            // 查询该用户有没有收藏该帖子
            $collect = CollectionModel::where(['userid' => $userid,'postid' => $postid])->find();

            $CollectStatus = $collect ? true : false;

            // 查询数据库
            $LoginUser = $this->UserModel->find($userid);

            // 用户存在在往下走
            if($LoginUser)
            {
                // 先获取帖子的访问人的ID
                $visit = $post['visit'];

                // s为空给一个空数组 不为空就转换为数组
                $visit = empty($visit) ? [] : explode(',', $visit);

                // 如果当前用户的ID 在 访问数组中就说明 已访问过，不在就说明没访问过
                if(!in_array($LoginUser['id'], $visit))
                {
                    //追加ID进去，然后在转换为字符串
                    $visit[] = $LoginUser['id'];
                    $visitStr = implode(',',$visit);

                    $PostData = [
                        'id' => $post['id'],
                        'visit' => $visitStr
                    ];

                    //更新这个帖子
                    $Post = PostModel::find($postid);

                    $Post->save($PostData);
                }
            }
        }

        // 查询评论
        $CommentList = CommentModel::withJoin(['user'])->where(['postid' => $postid])->order('id', 'asc')->order('level', 'asc')->select();
        
        // 递归处理评论数据
        $CommentList = CommentTree($CommentList,0,$LoginUser);

        // 查询本周的热议帖子
        $PostWeek = CommentModel::withJoin(['post'],'LEFT')->field('count(*) as num,post.title,post.id,comment.id')->whereWeek('comment.createtime')->group('comment.postid')->order(['num'=>'desc'])->limit(10)->select();
        
        

        return View::fetch('',[
            'post' => $post,
            'CommentList' => $CommentList,
            'PostWeek' => $PostWeek,
            'CollectStatus' => $CollectStatus
        ]);

    }

    // 签到功能
    public function sign()
    {
        if($this->request->isAjax())
        {
            $LoginUser = $this->LoginUser ? $this->LoginUser : [];

            if(empty($LoginUser))
            {
                $this->error('请先登录');
                
            }

            // 用户Id
            $userid = isset($LoginUser['id']) ? $LoginUser['id'] : 0;

            

            // 查询数据库
            $LoginUser = $this->UserModel->find($userid);

            // 没有找到这个人
            if(!$LoginUser)
            {
                //清除掉伪造的cookie缓存
                cookie('LoginUser', null);
                $this->error('非法登录');
                
            }

            // 查询当天内用户是否有签到记录
            $where = [
                'userid' => $userid,
                'state' => 4
            ];
            
            $record = $this->RecordModel->whereDay('createtime')->where($where)->find();

            if($record)
            {
                $this->error('您已签到，无须重复签到');
                
            }

            // 开启事务
            $this->UserModel->startTrans();
            $this->RecordModel->startTrans();

            // 查询签到积分
            $SignPoint =$this->ConfigModel->where(['key'=>'SignPoint'])->value('value');
            $SignPoint = abs(intval($SignPoint)) > 0 ? abs(intval($SignPoint)) : 5;

            // 当前时间
            $now = date("Y-m-d H:i", time());

            $RecordData = [
                'point' => $SignPoint,
                'content' => "【签到】$now 签到 获得 $SignPoint 积分",
                'state' => 4,
                'userid' => $userid
            ];
            
            try {
                validate(ReacrdValidate::class)->check($RecordData);
            } catch (ValidateException $e) {
                $this->error($e->getError());
            }
            
            $RecordStatus = $this->RecordModel->save($RecordData);

            //用户积分
            $UserPoint = $LoginUser['point'];

            //更新用户积分
            $UpdatePoint = bcadd((String)$UserPoint,(String)$SignPoint);

            //更新数据
            $UserData = [
                'point' => $UpdatePoint
            ];

            $UserStatus = $LoginUser->save($UserData);

            if($UserStatus !== true)
            {
                $this->RecordModel->rollback();
                $this->error($LoginUser->getError());
            }

            //两个动作都要同时成功才提交事务
            if($RecordStatus !== true || $UserStatus !== true)
            {
                $this->RecordModel->rollback();
                $this->UserModel->rollback();
                $this->error('签到失败');
            }else
            {
                //提交事务
                $this->UserModel->commit();
                $this->RecordModel->commit();
                $this->success("签到成功 获得{$SignPoint}积分");
            }
        }
    }

    // 登录
    public function login()
    {
        // 获取cookie
        $LoginUser = !empty(cookie('LoginUser')) ? cookie('LoginUser') : '';

        if(!empty($LoginUser))
        {
            $UserList = UserModel::column('id,salt');

            // 存放登录的id
            $userid = 0;

            foreach($UserList as $item)
            {
                $ID = md5($item['id'].$item['salt']);

                if($LoginUser == $ID)
                {
                    $userid = $item['id'];
                    break;
                }
            }

            $User = UserModel::find($userid);

            if(!$User)
            {
                // 清除cookie
                cookie('LoginUser',null);

                $this->error('非法登录','home/index/login');
            }

            $this->success('你已经登录成功了，无需重新登录',(String)url('home/index/index'));
        }


        if($this->request->isPost())
        {
            // 接收全部的参数
            $params = $this->request->param();

            // 验证验证码是否正确
            if(!captcha_check($params['vercode']))
            {
                $this->error('验证码错误，请重新输入');
                
            }

            // 查询用户
            $user = $this->UserModel->where(['email' => $params['email']])->find();

            // 判断该用户是否存在
            if(!$user)
            {
                $this->error('该用户不存在');
                
            }

            // 接收的密码进行加密
            $password = md5($params['password'] . $user['salt']);

            // 判断接收的密码跟用户表的密码是否一致
            if($password != $user['password'])
            {
                $this->error('密码错误。请重新输入');
                
            }

            // 由于设置cookie是用id来设置，可以在客户端看到cookie的值，所以需要加密
            $LoginUser = md5($user['id'] . $user['salt']);

            // 由于tp6的cookie只能存字符串或者json字符串,所以这里就不封装cookie数据,只存登录的用户id为cookie,再通过中间件传值
            cookie('LoginUser',$LoginUser);

            $this->success('登录成功','/home/user/index');
        }
        return View::fetch();
    }

    // 注册
    public function register()
    {
        // 获取cookie
        $LoginUser = !empty(cookie('LoginUser')) ? cookie('LoginUser') : '';

        if(!empty($LoginUser))
        {
            $UserList = UserModel::column('id,salt');

            // 存放登录的id
            $userid = 0;

            foreach($UserList as $item)
            {
                $ID = md5($item['id'].$item['salt']);

                if($LoginUser == $ID)
                {
                    $userid = $item['id'];
                    break;
                }
            }

            $User = UserModel::find($userid);

            if(!$User)
            {
                // 清除cookie
                cookie('LoginUser',null);

                $this->error('非法登录','home/index/login');
                
            }

            $this->success('你已经登录成功了，无需重新登录',(String)url('home/index/index'));
            

        }

        if($this->request->isPost())
        {
            // 接收所有的参数
            $params = $this->request->param();

            // 验证码是否正确
            if(!captcha_check($params['vercode']))
            {
                $this->error('验证码错误，请重新输入');
                
            }

            // 判断密码于确认密码是否一致
            if($params['password'] != $params['repass'])
            {
                $this->error('密码与确认密码不一致，请重新输入');
                
            }

            // 获取注册赠送的积分
            $point = $this->ConfigModel->where(['key' => 'RegisterPoint'])->value('value');

            // 生成密码盐
            $salt = build_ranstr();

            // 加密
            $password = md5($params['password'] . $salt);

            // 封装注册数据
            $data = [
                'email' => $params['email'],
                'nickname' => $params['nickname'],
                'password' => $password,
                'salt' =>  $salt,
                'point' => $point,
                'sex' => 0,
                'vip' => 1,
                'auth' => 0,
            ];

            try {
                validate(UserValidate::class)->check($data);
            } catch (ValidateException $e) {
                // 捕获异常
                $this->error($e->getError());
            }

            // 插入数据库
            $result = $this->UserModel->save($data);

            if($result !== true)
            {
                $this->error('注册失败');
                
            }else{
                $this->success('注册成功','home/index/login');
                
            }

        }

        // 输出视图
        return View::fetch();
    }

    public function logout()
    {
        cookie('LoginUser',null);
        $this->success('已退出账号',(String)url('home/index/index'));
        
    }


    // 邮箱认证
    public function email()
    {
        // 接收参数
        $auth = $this->request->param('auth','','trim');

        // 查询全部用户的Email以及id
        $userList = $this->UserModel->column('id,email,salt,auth');

        // 定义存放用户id的变量
        $userid = 0;

        // 循环用户的数据
        foreach($userList as $item)
        {
            // 先把循环出来的用户邮箱+密码盐加密再比对
            $EmailSalt = md5($item['email'] . $item['salt']);

            // 判断是否一致
            if($auth == $EmailSalt)
            {
                // 如果一致就赋值
                $userid = $item['id'];
                break;
            }
        }

        // 如果找不到
        if(!$userid)
        {
            $this->error('用户不存在');
        }
        

        // 封装更新数据
        $UserData = [
            'auth' => 1
        ];

        // 更新数据
        $User = UserModel::find($userid);

        // 更新数据
        $result = $User->save($UserData);

        // 如果不同浏览器或者用手机端验证，跳转到用户中心需要登录，所以需要在这里设置cookie

        // 通过匹配获取的用户id去查询该用户的数据
        $user = $this->UserModel->where(['id' => $userid])->field('id,salt')->find();

        // id + salt 进行加密
        $LoginUser = md5($user['id'] . $user['salt']);

        // 设置cookie
        cookie('LoginUser',$LoginUser);

        if($result !== true)
        {

            $this->error('认证失败,请稍后重试','/home/user/profile');
        }else{
            // 认证成功
            $this->success('认证成功','/home/user/profile');
        }
    }

    // 验证码
    public function vercode()
    {
        return Captcha::create('vercode');
    }
}
